package com.erbao.io.netty.refactor;

import com.erbao.SleepUtil;
import com.erbao.io.netty.Person;
import com.erbao.io.netty.refactor.rpc.proxy.MyProxy;
import com.erbao.io.netty.refactor.rpc.Dispatcher;
import com.erbao.io.netty.refactor.service.Car;
import com.erbao.io.netty.refactor.service.Fly;
import com.erbao.io.netty.refactor.service.impl.MyCar;
import com.erbao.io.netty.refactor.service.impl.MyFly;
import com.erbao.io.netty.refactor.transport.MyHttpRequestHandler;
import com.erbao.io.netty.refactor.transport.MyHttpServerServlet;
import com.erbao.io.netty.refactor.transport.PkgMsgDecoder;
import com.erbao.io.netty.refactor.transport.ServerRequestHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.junit.Test;

import java.net.InetSocketAddress;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 1.需求：写一个RPC:
 * 2.来回通信，连接数量，拆包、解包
 * 3.动态代理，序列化，反序列化，自定义协议封装
 * 4.客户端连接池
 * 5.RPC通俗解释：像调用本地方法一样调用远程方法，Java的面向接口开发，采用动态代理（feign是不是这么实现的？）
 * @author CaoBaoYin
 * @since 22/10/22 19:27
 */
public class MyRPCTest {

    @Test
    public void startServer(){
        registe();

        NioEventLoopGroup boss = new NioEventLoopGroup(50);
        NioEventLoopGroup worker = boss;

        ServerBootstrap server = new ServerBootstrap();
        ChannelFuture bind = server.group(boss, worker).channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel channel) throws Exception {
                        System.out.println("server accept port:"+channel.remoteAddress().getPort());
                        ChannelPipeline pipeline = channel.pipeline();

                        /*自定义的rpc
                        * 关注了粘包和拆包问题，header + body，header中会有body的大小*/
                        /*pipeline.addLast(new PkgMsgDecoder());
                        pipeline.addLast(new ServerRequestHandler());*/

                        /*传输协议 http 。可以自己写编解码，也可以使用netty提供的一套*/
                        pipeline.addLast(new HttpServerCodec());
                        pipeline.addLast(new HttpObjectAggregator(1024 * 512));
                        pipeline.addLast(new MyHttpRequestHandler());
                    }
                }).bind(new InetSocketAddress("localhost", 9090));

        try {
            // 第一个sync确保绑定成功，第二个sync服务端一直等待关闭，保证服务阻塞
            bind.sync().channel().closeFuture().sync();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private static void registe() {
        MyCar myCar = new MyCar();
        MyFly myFly = new MyFly();
        Dispatcher dispatcher = Dispatcher.dispatcher;
        dispatcher.register(Car.class.getName(), myCar);
        dispatcher.register(Fly.class.getName(), myFly);
    }

    @Test
    public void startHttpServer() {
        registe();

        Server server = new Server(new InetSocketAddress("localhost", 9090));
        ServletContextHandler contextHandler = new ServletContextHandler(server, "/");
        server.setHandler(contextHandler);
        contextHandler.addServlet(MyHttpServerServlet.class, "/");

        try {
            server.start();
            server.join();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Test
    public void get () {
        // new Thread(this::startServer).start();

        AtomicInteger atomicInteger = new AtomicInteger(0);
        /*传输单个参数*/
        /*for (int i = 0; i < 2; i++) {
            new Thread(()->{
                Car car = MyProxy.proxyGet(Car.class);
                String arg = "hahha-" + atomicInteger.incrementAndGet();
                String result = car.xxoo(arg);
                System.out.println(result+" client发送参数："+arg);
            }).start();
        }*/

        /*传输对象*/
        for (int i = 0; i < 1; i++) {
            new Thread(()->{
                Car car = MyProxy.proxyGet(Car.class);
                int incrementAndGet = atomicInteger.incrementAndGet();
                String name = "hahha-" + incrementAndGet;
                Person person = car.oxox(name, incrementAndGet);
                System.out.println(person+" client发送参数："+name+":"+incrementAndGet);
            }).start();
        }

        // System.out.println("执行结束！！！");

        SleepUtil.sleep(30000);

    }

}

